#pragma once
#include <QString>
#include <QIcon>
#include <QUuid>
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
#include <QDebug>

#include "base.qpb.h"
#include "gateway.qpb.h"
#include "user.qpb.h"
#include "message.qpb.h"
#include "friend.qpb.h"
#include "transmite.qpb.h"
#include "file.qpb.h"
#include "notify.qpb.h"
#include "speech.qpb.h"

namespace model
{
//////////////////////////////////////////////////////////////
/// 工具函数
/////////////////////////////////////////////////////////////
static inline QString getFileName(const QString& path)
{
    QFileInfo fileInfo(path);
    return fileInfo.fileName();
}
//封装宏作为打印日志的方式
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))
#define LOG() qDebug() << TAG

static inline QString formatTime(int64_t timestamp)
{
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    return dateTime.toString("MM-dd HH:mm:ss");
}
static inline int64_t getTime()
{
    return QDateTime::currentSecsSinceEpoch();
}
//将QByteArray转成 QIcon
static inline QIcon makeIcon(const QByteArray& byteArray)
{
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon(pixmap);
    return icon;
}
//读写文件操作
//从指定文件中 读取所有二进制内容 得到一个QByteArray
static inline QByteArray loadFileToByteArray(const QString& path)
{
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok)
    {
        qDebug() << "文件打开失败！";
        return QByteArray();
    }
    QByteArray content = file.readAll();
    file.close();
    return content;
}
//把得到一个QByteArray 写道文件里
static inline void writeByteArrayToFile(const QString& path, const QByteArray& content)
{
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok)
    {
        qDebug() << "文件打开失败！";
        return;
    }

    file.write(content);
    file.flush();
    file.close();
    return;
}
//////////////////////////////////////////////////////////////
/// 用户信息
/////////////////////////////////////////////////////////////
class UserInfo
{
public:
    QString userID = "";        //用户id
    QString nickname = "";      //用户昵称
    QString description = "";   //用户签名
    QString phone = "";         //用户手机号
    QIcon avatar;               //用户头像

    //从 protobuf UserInfo 转成 model::UserInfo
    void load(const xchat::UserInfo& pbUserInfo)
    {
        userID = pbUserInfo.userId();
        nickname = pbUserInfo.nickname();
        description = pbUserInfo.description();
        phone = pbUserInfo.phone();
        //头像判空
        if(pbUserInfo.avatar().isEmpty())
        {
            //使用默认头像
            avatar = QIcon(":/resource/image/defaultAvatar.png");
            LOG() << "[load] 用户头像加载失败 pbUserInfo.avatar().isEmpty() 使用默认头像!";
            return;
        }

        avatar = makeIcon(pbUserInfo.avatar());
    }
};

enum Message_Type
{
    TEXT_TYPE,      //文本消息
    IMAGE_TYPE,
    FILE_TYPE,
    SPEECH_TYPE     //语音消息
};

class Message
{
public:
    QString messageID = "";
    QString chatSessionID = "";      //属于哪个会话
    QString time = "";               //时间 06-12：00
    Message_Type messageType;        //消息类型
    UserInfo sender;                 //发送者的信息
    QByteArray content;              //消息内容
    QString fileID = "";             //如果是文件消息 为文件标识 文本消息为""
    QString fileName = "";           //文件名称 出了文件 语音图像文本为""

    //extraInfo 在消息类型为文件 时候 额外文件名
    static Message makeMessage(Message_Type messageType, const QString& chatSessionID, const UserInfo& sender,
        const QByteArray& content, const QString& extraInfo)
    {
        if(messageType == TEXT_TYPE)
        {
            return makeTextMessage(chatSessionID, sender, content);
        }
        else if(messageType == IMAGE_TYPE)
        {
            return makeImageMessage(chatSessionID, sender, content);
        }
        else if(messageType == FILE_TYPE)
        {
            return makeFileMessage(chatSessionID, sender, content, extraInfo);
        }
        else if(messageType == SPEECH_TYPE)
        {
            return makeSpeechMessage(chatSessionID, sender, content);
        }
        else
        {
            //触发未知消息
            return Message();
        }

    }
    //将 protobuf Message 转成 model::Message
    void load(const xchat::MessageInfo& messageInfo)
    {
        messageID = messageInfo.messageId();
        chatSessionID = messageInfo.chatSessionId();
        time = formatTime(messageInfo.timestamp());
        sender.load(messageInfo.sender());
        auto type = messageInfo.message().messageType();
        //根据不同的类型 解析不同的字段
        if (type == xchat::MessageTypeGadget::MessageType::STRING)
        {
            this->messageType = TEXT_TYPE;
            this->content = messageInfo.message().stringMessage().content().toUtf8();
        }
        else if (type == xchat::MessageTypeGadget::MessageType::IMAGE)
        {
            this->messageType = IMAGE_TYPE;
            if (messageInfo.message().imageMessage().hasImageContent())
            {
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if (messageInfo.message().imageMessage().hasFileId())
            {
                this->fileID = messageInfo.message().imageMessage().fileId();
            }
        }
        else if (type == xchat::MessageTypeGadget::MessageType::FILE)
        {
            this->messageType = FILE_TYPE;
            if (messageInfo.message().fileMessage().hasFileContents())
            {
                this->content = messageInfo.message().fileMessage().fileContents();
            }
            if (messageInfo.message().fileMessage().hasFileId())
            {
                this->fileID = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();
        }
        else if (type == xchat::MessageTypeGadget::MessageType::SPEECH)
        {
            this->messageType = SPEECH_TYPE;
            if (messageInfo.message().speechMessage().hasFileContents())
            {
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if (messageInfo.message().speechMessage().hasFileId())
            {
                this->fileID = messageInfo.message().speechMessage().fileId();
            }
        }
        else
        {
            // 错误的类型, 啥都不做了, 只是打印一个日志
            LOG() << "非法的消息类型! type=" << type;
        }
    }
private:
    static QString makeID()
    {
        return "M" + QUuid::createUuid().toString().sliced(25, 12);
    }
    static Message makeTextMessage(const QString& chatSessionID, const UserInfo& sender, const QByteArray& content)
    {
        Message message;
        //messageID 需要是唯一的
        message.messageID = makeID();
        message.messageType = TEXT_TYPE;
        message.chatSessionID = chatSessionID;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        //文本消息为空
        message.fileID = "";
        message.fileName = "";
        return message;
    }
    static Message makeImageMessage(const QString& chatSessionID, const UserInfo& sender, const QByteArray& content)
    {
        Message message;
        //messageID 需要是唯一的
        message.messageID = makeID();
        message.messageType = IMAGE_TYPE;
        message.chatSessionID = chatSessionID;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.fileID = "";
        //图片消息为空
        message.fileName = "";
        return message;
    }
    static Message makeFileMessage(const QString& chatSessionID, const UserInfo& sender, const QByteArray& content, const QString& fileName)
    {
        Message message;
        //messageID 需要是唯一的
        message.messageID = makeID();
        message.messageType = FILE_TYPE;
        message.chatSessionID = chatSessionID;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.fileID = ""; //TODO
        message.fileName = fileName;
        return message;
    }
    static Message makeSpeechMessage(const QString& chatSessionID, const UserInfo& sender, const QByteArray& content)
    {
        Message message;
        //messageID 需要是唯一的
        message.messageID = makeID();
        message.messageType = SPEECH_TYPE;
        message.chatSessionID = chatSessionID;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.fileID = "";
        //语音消息为空
        message.fileName = "";
        return message;
    }
};

//聊天会话信息
class ChatSessionInfo
{
public:
    //
    void load(const xchat::ChatSessionInfo& chatSessionInfo)
    {
        this->chatSessionID = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();
        if (chatSessionInfo.hasSingleChatFriendId())
        {
            this->userID = chatSessionInfo.singleChatFriendId();
        }
        // 最新消息处理
        if (chatSessionInfo.hasPrevMessage() && !chatSessionInfo.prevMessage().messageId().isEmpty())
        {
            lastMessage.load(chatSessionInfo.prevMessage());
        }
        // 头像处理
        if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty())
        {
            // 已经有头像了, 直接设置这个头像
            this->avatar = makeIcon(chatSessionInfo.avatar());
        }
        else
        {
            // 如果没有头像, 则根据当前会话是单聊还是群聊, 使用不同的默认头像.
            if (userID != "")
            {
                // 单聊
                this->avatar = QIcon(":/resource/image/defaultAvatar.png");
            }
            else
            {
                // 群聊
                this->avatar = QIcon(":/resource/image/groupAvatar.png");
            }
        }
    }

    QString chatSessionID = "";      //会话id
    QString chatSessionName = "";    //会话名称， 单聊 群聊 名不一样
    Message lastMessage;             //表示最新消息 从会话外面看有刚发的一条消息
    QIcon avatar;                    //会话头像 单聊 群聊
    QString userID = "";             //用户id 单聊拿一个 群聊拿一群
};

} //end model
